1. Field of the Invention
The invention relates generally to method and apparatus carried out on a digital computer for converting a source program to an object code, and more particularly to an optimizing method and apparatus for defining visibility boundaries in compiled code.
2. Description of the Prior Art
Optimizing compilers are described in Aho, Sethi and Ullman, "Compilers: Principles, Techniques and Tools", Addison-Wesley (1986), Chpt. 10, pp. 585-722.
Other prior art examples include:
U.S. Pat. No. 4,567,574 discloses a method for optimizing instruction path lengths in a compilation of COBOL source code with reference to PERFORM statements.
U.S. Pat. No. 4,953,084 discloses an optimizing compiler and method using variable ranges to support symbolic debugging of optimized code. The compiler maintains a list of ranges in a range table.
U.S. Pat. No. 5,107,418 discloses a method for representing scalar data dependencies for an optimizing compiler with a global scalar data dependency graph being created to represent all of the scalar objects in an entire program. Kill sets are calculated by building local graphs.
PCT international application WO 91/20030 discloses a modular compilation technique utilizing a fully integrated hierarchical representation as a common intermediate representation to compile source code programs written in one or more procedural programming languages into an executable object code.
Japan patent JP 63-292338 discloses an optimized program debugging system that informs a debug user of rows changed by optimization, variable names to which values are not set, etc., in an object program optimized by a compiler.
An optimizing compiler can eliminate code determined to be unnecessary for the correct execution of the procedure being compiled. In some cases, stores to the spaces in memory allocated for different variables can be eliminated. This is commonly called Store Elimination. In other instances, loads of the current variables are eliminated if determined that those values could not have changed since last loaded and the last loaded value is still available for use. This is commonly called Load Elimination.
A problem with many prior art optimizing compilers is that they do not effectively process asynchronous events. If an asynchronous event such as a program exception or some form of interprocess communication initiated by another process occurs, the processing which takes place could attempt to either reference or modify some variables in the source program. At the point at which an asynchronous event may occur, stores to variables that could be referenced by the event must be current and following the same point in the procedure, the values of all variables that could have been modified must be loaded from their home storage locations allocated for them.
There are three conventional approaches to the problem where there is a possibility that the actions of some other asynchronously executing program might alter the value of program variables. The first is to simply disable all optimization in programs which might be subject to such asynchronous activity. This is generally effective, but it may severely impact program execution speed.
A second approach is to mark the asynchronously referenced/modified variables as volatile, so that the current values of the variables must always be maintained in main storage, and any references to those variables must be satisfied by fetching the value from main storage. This represents a significant improvement over the first approach, but it still does not achieve the best optimization. For instance, it may be known that an asynchronous modification may occur only between certain lines of a program due to known interactions between the two programs. However, the second approach maintains the volatile variables throughout the entire program.
A third conventional approach is to kill all variables or all variables of some class at certain points in a program. Thus, if it is known that some asynchronous activity might occur between certain lines, then values of variables not yet stored in main storage would be stored at or before a certain line, and all references to variables in or after a certain line would fetch values afresh from main storage. The third approach is most commonly used as a simple approach to the aliasing problem in the case of procedure calls since calls to other procedures, particularly separately compiled procedures may reference or modify variables in some unseen fashion. This approach degrades the performance of the generated code because all variables or all of those of a certain class, such as the external variables in a program are affected and the killing of all variables must occur during every execution of the optimized program, even though the asynchronous activity may only occur in only one out of a thousand program executions.